﻿// -----------------------------------------------------------------
// CTS Helper Plugin
// -----------------------------------------------------------------
// Yêu cậu khi import plugin:
//   + jQuery Plugin
// -----------------------------------------------------------------
'use strict';
/**
* @class
* Định nghĩa class 'cts.helper.BrowserHelper'
*/
cts.lang.Class.declare('cts.helper.BrowserHelper', {
    _static: {
        // Định nghĩa loại đối tượng trình duyệt
        type: {
            msie: 'msie',
            firefox: 'firefox',
            chrome: 'chrome',
            opera: 'opera',
            safari: 'safari',
            other: 'other'
        },
        /** 
        * Lấy loại trình duyệt người dùng
        * @param ua: userAgent
        * @returns loại trình duyệt
        */
        getType: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            if (this.getIEVersion(ua) !== -1) {
                return this.type.msie;
            }
            if (ua.toLowerCase().indexOf(this.type.firefox) >= 0) {
                return this.type.firefox;
            }
            if (ua.toLowerCase().indexOf(this.type.safari) >= 0) {
                if (ua.toLowerCase().indexOf(this.type.chrome) >= 0) {
                    return this.type.chrome;
                }
                return this.type.safari;
            }
            if (ua.toLowerCase().indexOf(this.type.opera) >= 0) {
                return this.type.opera;
            }
            return this.type.other;
        },
        /** 
        * Lấy phiên bản của Internet Explorer
        * @param ua: userAgent
        * @returns phiên bản của Internet Explorer hoặc -1 nếu là trình duyệt khác.
        */
        getIEVersion: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            var rv = -1, re;
            if (navigator.appName === 'Microsoft Internet Explorer') {
                re = new RegExp('MSIE ([0-9]{1,}[\.0-9]{0,})');
                if (re.exec(ua) !== null) {
                    rv = parseFloat(RegExp.$1);
                }
            } else if (navigator.appName === 'Netscape') {
                re = new RegExp('Trident/.*rv:([0-9]{1,}[\.0-9]{0,})');
                if (re.exec(ua) !== null)
                    rv = parseFloat(RegExp.$1);
            }
            return rv;
        },
        /** 
        * Kiểm tra trình duyệt là IE
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isIE: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getType(ua) === this.type.msie;
        },
        /** 
        * Kiểm tra trình duyệt là nhỏ hơn IE8
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isIElt8: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getIEVersion(ua) < 8.0 && this.isIE(ua);
        },
        /** 
        * Kiểm tra trình duyệt là IE8
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isIE8: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getIEVersion(ua) === 8.0;
        },
        /** 
        * Kiểm tra trình duyệt là IE9
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isIE9: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getIEVersion(ua) === 9.0;
        },
        /** 
        * Kiểm tra trình duyệt là IE10
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isIE10: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getIEVersion(ua) === 10.0;
        },
        /** 
        * Kiểm tra trình duyệt là firefox
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isFireFox: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getType(ua) === this.type.firefox;
        },
        /** 
        * Kiểm tra trình duyệt là chrome
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isChrome: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getType(ua) === this.type.chrome;
        },
        /** 
        * Kiểm tra trình duyệt là safari
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isSafari: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return this.getType(ua) === this.type.safari;
        },
        /** 
        * Kiểm tra là thiết bị smartphone
        * @param ua: userAgent
        * @returns {Boolean}
        */
        isDevice: function (ua) {
            if (!ua) {
                ua = navigator.userAgent;
            }
            return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
        }
    }
});

/**
* @class
* Định nghĩa class 'cts.helper.DataHelper'
*/
cts.lang.Class.declare('cts.helper.DataHelper', {
    _static: {
        /**
        * Cắt khoảng trăng của cả hai bên của chuỗi
        * @param data: chuỗi dữ liệu
        * @returns chuỗi đã cắt
        */
        trim: function (data) {
            return $.trim(data.toString());
        },
        /**
        * Thay thế tất cả chuỗi
        * @param find: chuỗi tìm
        * @param replace: chuỗi thay thế
        * @param data: chuỗi dữ liệu
        * @returns chuỗi đã replace
        */
        replaceAll: function (find, replace, data) {
            var escFind = cts.helper.DataHelper.escapeRegExp(find);
            var re = new RegExp(escFind, 'g');
            return data.replace(re, replace);
        },
        /**
        * Escape chuỗi RegExp
        * @param data: chuỗi dữ liệu
        * @returns chuỗi đã escape
        */
        escapeRegExp: function (data) {
            return data.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
        },
        /**
        * Convert chuỗi boolean
        * @param data: chuỗi dữ liệu
        * @returns {Boolean}
        */
        toBoolean: function (data) {
            return data === true
                || data === 'True'
                || data === 'true'
                || data === '1';
        },
        /**
        * Convert chuỗi thành chuỗi latin
        * @param data: chuỗi dữ liệu
        * @param opt: đối tượng options
        * @returns chuỗi latin
        */
        toLatinString: function (data, opt) {
            // Khởi tạo biến cục bộ
            var latin = data;
            var delimiter = ' ';
            // Trường hợp data là un
            if (cts.helper.CheckHelper.isNull(data)) {
                return '';
            }
            // Trường hợp opt khác null
            if (opt) {
                // Lấy dấu phân cách
                if (typeof opt === 'string') {
                    delimiter = opt;
                } else if (opt.delimiter) {
                    delimiter = opt.delimiter;
                }
            }
            // Thay thế ký tự thường
            latin = latin.replace(/æ|å|ä|à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/g, 'a');
            latin = latin.replace(/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ/g, 'e');
            latin = latin.replace(/ì|í|ị|ỉ|ĩ/g, 'i');
            latin = latin.replace(/ø|ö|ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/g, 'o');
            latin = latin.replace(/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/g, 'u');
            latin = latin.replace(/ỳ|ý|ỵ|ỷ|ỹ/g, 'y');
            latin = latin.replace(/đ/g, 'd');
            latin = latin.replace(/ñ/g, 'n');
            // Thay thế ký tự in hoa
            latin = latin.replace(/Æ|Å|Ä|À|Á|Ạ|Ả|Ã|Â|Ầ|Ấ|Ậ|Ẩ|Ẫ|Ă|Ằ|Ắ|Ặ|Ẳ|Ẵ/g, 'A');
            latin = latin.replace(/È|É|Ẹ|Ẻ|Ẽ|Ê|Ề|Ế|Ệ|Ể|Ễ/g, 'E');
            latin = latin.replace(/Ì|Í|Ị|Ỉ|Ĩ/g, 'I');
            latin = latin.replace(/Ø|Ö|Ó|Ò|Ỏ|Õ|Ọ|Ô|Ố|Ồ|Ổ|Ỗ|Ộ|Ơ|Ớ|Ờ|Ở|Ỡ|Ợ/g, 'O');
            latin = latin.replace(/Ú|Ù|Ủ|Ũ|Ụ|Ư|Ứ|Ừ|Ử|Ữ|Ự/g, 'U');
            latin = latin.replace(/Ý|Ỳ|Ỷ|Ỹ|Ỵ/g, 'Y');
            latin = latin.replace(/Đ/g, 'D');
            latin = latin.replace(/Ñ/g, 'N');
            // Thay thế ký tự đặc biệt
            latin = latin.replace(/!|@|%|\^|\*|\(|\)|\+|\=|\<|\>|\?|\/|,|\.|\:|\;|\'| |\"|\&|\#|\[|\]|~|$|_/g, ' ');
            // Xóa ký tự không hợp lệ
            latin = latin.replace(/(^[^a-zA-Z0-9]+)|([^a-zA-Z0-9\-_\s])/g, '');
            // Thay thế khoảng trắng thành dấu phân cách
            latin = latin.replace(/\s+[\-_]*/g, delimiter);
            // Thay thế dấu phân cách '--', '__'
            latin = latin.replace(/-+-/g, '-');
            latin = latin.replace(/_+_/g, '_');
            // Trim ký tự ' ', '-' và '_'
            latin = latin.replace(/^[\s\-_]+|[\s\-_]+$/g, '');
            // Kết quả xử lý
            return latin;
        },
        /**
        * Convert tên thành tên tìm kiếm
        * @param data: chuỗi dữ liệu
        * @returns tên tìm kiếm
        */
        toSearchName: function (data) {
            // Khởi tạo biến cục bộ
            var result = data;
            var delimiter = '-';
            // Tiến hành convert chuỗi thành chuỗi latin
            result = cts.helper.DataHelper.toLatinString(result, delimiter)
            // Kết quả xử lý
            return result.toLowerCase();
        },
        /** 
        * Chuyển đổi mảng đối tượng thành đối tượng JSON
        * Cấu trúc:
        * - Mảng đối tượng:
        *   {
        *      'name' hoặc 'key': {String},
        *      'value': {Object}     
        *   }
        * @param arr: mảng đối tượng
        * @returns đối tượng JSON
        */
        toJSON: function (arr) {
            var json = {};
            $.each(arr, function () {
                var prop = this.name || this.key;
                if (json[prop] !== undefined) {
                    if (!json[prop].push) {
                        json[prop] = [json[prop]];
                    }
                    json[prop].push(this.value || '');
                } else {
                    json[prop] = this.value || '';
                }
            });
            return json;
        },
        /** 
        * Convert mảng đối tượng thành mảng tree
        * Cấu trúc:
        * - Mảng đối tượng:
        *   {
        *      'cd': {String},
        *      'pcd': {String}
        *   }
        * - Đối tượng mapping:
        *   {
        *      'cd': {String},
        *      'pcd': {String},
        *      'childs': {String}
        *   }
        * @param arr: mảng đối tượng
        * @param prt: mã node cha
        * @param nms: đối tượng mapping
        * @returns mảng tree
        */
        toTree: function (arr, prt, nms) {
            // Khởi tạo biến cục bộ
            var tree = [];
            var cd, pcd, node;
            var pChilds = nms ? nms.childs : 'childs';
            // Trường hợp tên thuộc tính childs không hợp lệ
            if (cts.helper.CheckHelper.isNull(pChilds)) {
                return [];
            }
            // Trường hợp prt là undefined
            if (!prt) {
                prt = '';
            }
            // Diệt danh sách đối tượng
            $.each(arr, function (i, obj) {
                // Lấy dữ liệu từ đối tượng
                cd = obj.cd;
                pcd = obj.pcd;
                // Trường hợp đối tượng mapping khác null
                if (nms) {
                    cd = obj[nms.cd];
                    pcd = obj[nms.pcd];
                }
                // Trường hợp prt là undefined
                if (!pcd) {
                    pcd = '';
                }
                // Trường hợp không tồn tại cd
                if (cd === undefined) {
                    return [];
                }
                // Trường hợp tồn tại parent
                if (pcd === prt) {
                    // Sao chép giá trị của đối tượng vào node
                    node = angular.copy(obj);
                    // Lấy danh sách childs
                    node[pChilds] = cts.helper.DataHelper.toTree(arr, cd, nms);
                    // Thêm vào danh sách kết quả
                    tree.push(node);
                }
            });
            // Kết quả xử lý
            return tree;
        },
        /**
        * Sao chép đối tượng
        * @param source: đối tượng nguồn
        * @param target: đối tượng đến
        * @returns đối tượng đã sao chép
        */
        copyObject: function (source, target) {
            // Trường hợp đối tượng source là null
            if (source === undefined || source === null) {
                // Kết thúc xử lý
                return target;
            }
            // Trường hợp đối tượng target là null
            if (target === undefined || target === null) {
                target = {};
            }
            // Duyệt các property trong đối tượng source
            for (var prop in source) {
                // Khởi tạo biến cục bộ
                var tmp;
                // Lấy giá trị từ đối tượng source [val]
                var val = source[prop];
                // Trường hợp val là đối tượng
                if ($.isPlainObject(val)) {
                    // Khởi tạo đối tượng
                    tmp = target[prop];
                    // Sao chép giá trị vào đối tượng
                    tmp = _fnCopyObject(val, tmp);
                }
                // Trường hợp val là mảng
                else if ($.isArray(val)) {
                    // Khởi tạo biến cục bộ
                    var t;
                    // Khởi tạo mảng [array]
                    tmp = [];
                    // Duyệt các phần tử trong array
                    $.each(val, function (i, s) {
                        // Sao chép giá trị vào đối tượng
                        t = cts.helper.DataHelper.copyObject(s, t);
                        // Thêm đối tượng vào array
                        tmp.push(t);
                    });
                }
                // Trường hợp ngược lại
                else {
                    // Gán giá trị vào biến tmp
                    tmp = val;
                }
                // Gán giá trị vào đối tượng target
                target[prop] = tmp;
            }
            // Kết thúc xử lý
            return target;
        }
    }
});
/**
* @class
* Định nghĩa class 'cts.helper.CheckHelper'
*/
cts.lang.Class.declare('cts.helper.CheckHelper', {
    _static: {
        /** 
        * Kiểm tra dữ liệu null
        * @param data: dữ liệu
        * @returns {Boolean}
        */
        isNull: function (data) {
            return data === undefined
                || data === 'undefined'
                || data === null
                || data.length === 0
                || cts.helper.DataHelper.trim(data) === '';
        },
        /** 
        * Kiểm tra element là select
        * @param elem: element
        * @returns {Boolean}
        */
        isSelect: function (elem) {
            return $(elem).is('select');
        },
        /** 
        * Kiểm tra element là list
        * @param elem: element
        * @returns {Boolean}
        */
        isList: function (elem) {
            return $(elem).is('ul') || $(elem).is('ul');
        },
        /** 
        * Kiểm tra element là checkbox
        * @param elem: element
        * @returns {Boolean}
        */
        isCheckBox: function (elem) {
            return $(elem).is(':input[type=checkbox]');
        },
        /** 
        * Kiểm tra element là radio
        * @param elem: element
        * @returns {Boolean}
        */
        isRadio: function (elem) {
            return $(elem).is(':input[type=radio]');
        },
        /** 
        * Kiểm tra element là button
        * @param elem: element
        * @returns {Boolean}
        */
        isButton: function (elem) {
            var rs = $(elem).is(':button')
                || $(elem).is(':input[type=button]')
                || $(elem).is(':input[type=submit]');
            if (cts.helper.BrowserHelper.isIE8()) {
                return rs && $(elem).attr('type') !== 'file';
            }
            return rs;
        },
        /**
        * Kiểm tra element có thể focus
        * @param elem: element
        * @returns {Boolean}
        */
        isFocusable: function (elem) {
            var rs = $(elem).is(':visible')
                && $(elem).is(':enabled')
                && $(elem).css('visibility') !== 'hidden'
                && $(elem).attr('type') !== 'hidden' // for IE bug ?
                && $(elem).attr('tabindex') !== '-1'
                && !$(elem).prop('readonly');
            return rs;
        }
    }
});
/**
* @class
* Định nghĩa class 'cts.helper.ResourceHelper'
*/
cts.lang.Class.declare('cts.helper.ResourceHelper', {
    _static: {
        /**
        * Lấy chuỗi message từ resource.
        * @returns chuỗi message
        */
        getMessage: function () {
            // Trường hợp chuỗi tham số là null
            if (cts.helper.CheckHelper.isNull(arguments)) {
                return '';
            }
            // Trường hợp đối tượng messages là null
            if (cts.helper.CheckHelper.isNull(messages)) {
                return arguments[0];
            }
            // Khởi tạo biến cục bộ
            var locale = cts.helper.PageHelper.getLang();
            var msgLocale = messages[locale];
            // Trường hợp không tồn tại ngôn ngữ
            if (cts.helper.CheckHelper.isNull(msgLocale)) {
                return arguments[0];
            }
            // Lấy chuỗi message
            var msg = msgLocale[arguments[0]];
            // Trường hợp không tồn tại chuỗi message
            if (cts.helper.CheckHelper.isNull(msg)) {
                return arguments[0];
            }
            // Trường hợp số lượng tham số là 1
            if (arguments.length === 1) {
                return msg;
            }
            // Khởi tạo biến dùng trong loop
            var ptn = '';
            var nm = '';
            // Duyệt danh sách tham số
            for (var i = 1; i < arguments.length; i++) {
                ptn = '{' + (i - 1) + '}';
                nm = cts.helper.ResourceHelper.getName(arguments[i]);
                msg = cts.helper.DataHelper.replaceAll(ptn, nm, msg);
            }
            // Kết thúc xử lý
            return msg;
        },
        /**
        * Lấy chuỗi name từ resource.
        * @returns chuỗi name
        */
        getName: function () {
            // Trường hợp chuỗi tham số là null
            if (cts.helper.CheckHelper.isNull(arguments)) {
                return '';
            }
            // Trường hợp đối tượng names là null
            if (cts.helper.CheckHelper.isNull(names)) {
                return arguments[0];
            }
            // Khởi tạo biến cục bộ
            var locale = cts.helper.PageHelper.getLang();
            var nmLocale = names[locale];
            // Trường hợp không tồn tại ngôn ngữ
            if (cts.helper.CheckHelper.isNull(nmLocale)) {
                return arguments[0];
            }
            // Lấy chuỗi name
            var nm = nmLocale[arguments[0]];
            // Trường hợp không tồn tại chuỗi name
            if (cts.helper.CheckHelper.isNull(nm)) {
                return arguments[0];
            }
            // Kết thúc xử lý
            return nm;
        }
    }
});
/**
* @class
* Định nghĩa class 'cts.helper.ValidateHelper'
*/
cts.lang.Class.declare('cts.helper.ValidateHelper', {
    _static: {
        /**
        * Gen thông báo không hợp lệ
        * @param alerts: đối tượng thông báo
        * @returns {Boolean}
        */
        genAlert: function (alerts) {
            // Khởi tạo biến cục bộ
            var focusId = '';
            // Duyệt đối tượng thông báo
            for (var idx in alerts) {
                // Khởi tạo biến cục bộ
                var alert = alerts[idx];
                var isValid = true;
                // Tạo thẻ thông báo
                var div = $('<div>');
                div.attr('id', alert.id + '_invalid');
                div.addClass('alert alert-danger');
                // Tạo thẻ danh sách thông báo
                var ul = $('<ul>');
                // Duyệt danh sách kiểm tra
                for (var valIdx in alert.valids) {
                    // Khởi tạo biến cục bộ
                    var val = alert.valids[valIdx];
                    // Trường hợp có dữ liệu không hợp lệ
                    if (!val.valid) {
                        // Gán đối
                        isValid = false;
                        // Tạo thẻ mục thông báo
                        var li = $('<li>');
                        li.text(val.message);
                        // Thêm vào thẻ danh sách thông báo
                        ul.append(li);
                    }

                }
                // Thêm vào thẻ thông báo
                div.append(ul);
                // Xóa thẻ thông báo trước
                $('#' + alert.id).removeClass('invalid');
                $('#' + alert.id + '_invalid').remove();
                // Trường hợp có dữ liệu không hợp lệ
                if (!isValid) {
                    $('#' + alert.id).addClass('invalid');
                    $('#' + alert.id).parent().append(div);
                    // Lấy tabindex của mục hiện tại
                    var cti = parseInt($('#' + alert.id).attr('tabindex'));
                    if (isNaN(cti)) {
                        cti = -1;
                    }
                    // Lấy tabindex của mục focus
                    var fti = parseInt($('#' + focusId).attr('tabindex'));
                    if (isNaN(fti)) {
                        fti = -1;
                    }
                    // Trường hợp tabindex của mục hiện tại nhỏ hơn mục focus
                    if (fti === -1 || cti < fti) {
                        focusId = alert.id;
                    }
                }
            }
            // Set focus đối tượng
            $('#' + focusId).focus();
        },
        /**
        * Kiểm tra tính hợp lệ dữ liệu.
        * @param obj: đối tượng kiểm tra
        * @returns {Boolean}
        */
        verify: function (obj) {
            // Khởi tạo biến cục bộ
            var rs = true;
            var alerts = [];
            // Duyệt đối tượng kiểm tra
            for (var id in obj) {
                // Khởi tạo biến cục bộ
                var input = obj[id];
                var alert = { id: id, valids: [] };
                // Duyệt danh sách rules
                for (var idx in input.rules) {
                    var rule = input.rules[idx];
                    var fnVal = cts.helper.ValidateHelper[rule];
                    // Tiến hành kiểm tra dữ liệu theo rule
                    var val = fnVal(input);
                    // Trường hợp có dữ liệu không hợp lệ
                    if (!val.valid) {
                        rs = false;
                    }
                    // Thêm vào danh sách đối tượng valid
                    alert.valids.push(val);
                }
                // Thêm vào danh sách đối tượng alert
                alerts.push(alert);
            }
            // Tiến hành gen thông báo không hợp lệ
            cts.helper.ValidateHelper.genAlert(alerts);
            // Kết thúc xử lý
            return rs;
        },
        /**
        * Kiểm tra regex.
        * @param obj: đối tượng kiểm tra
        * @param regex: đối tượng regex
        * @returns đối tượng validate
        */
        regex: function (obj, regex) {
            // Khởi tạo biến cục bộ
            var rs = { valid: true, message: undefined };
            // Trường hợp dữ liệu là null
            if (cts.helper.CheckHelper.isNull(obj.data)) {
                // Kết thúc xử lý
                return rs;
            }
            // Khởi tạo đối tượng RegExp
            var re = new RegExp(regex);

            //alert(regex.test(obj.data));

            // Kiểm tra tính hợp lệ
            if (regex.test(obj.data) === false) {
                // Gán giá trị trả về
                rs.valid = false;
                rs.message = cts.helper.ResourceHelper.getMessage(
                    'E.MSG.00006',
                    obj.messageParam);
                // Kết thúc xử lý
                return rs;
            }
            // Kết thúc xử lý
            return rs;
        },
        /**
        * Kiểm tra required.
        * @param obj: đối tượng kiểm tra
        * @returns đối tượng validate
        */
        required: function (obj) {
            // Khởi tạo biến cục bộ
            var rs = { valid: true, message: undefined };
            // Kiểm tra tính hợp lệ
            if (cts.helper.CheckHelper.isNull(obj.data)) {
                // Gán giá trị trả về
                rs.valid = false;
                rs.message = cts.helper.ResourceHelper.getMessage(
                    'E.MSG.00001',
                    obj.messageParam);
                // Kết thúc xử lý
                return rs;
            }
            // Kết thúc xử lý
            return rs;
        },
        /**
        * Kiểm tra code.
        * @param obj: đối tượng kiểm tra
        * @returns đối tượng validate
        */
        chkcode: function (obj) {
            var re = /^[a-zA-Z0-9_\-]+$/g;
            // Kết thúc xử lý
            return cts.helper.ValidateHelper.regex(obj, re);
        },
        /**
        * Kiểm tra name.
        * @param obj: đối tượng kiểm tra
        * @returns đối tượng validate
        */
        chkname: function (obj) {
            var re = /[^`~!@%\#$%\^\&\*\(\)\+\=\{\}\[\]\\\|\:\;\'\"\<\>,\.\/\?]+/g;
            // Kết thúc xử lý
            return cts.helper.ValidateHelper.regex(obj, re);
        },
        /**
        * Kiểm tra username.
        * @param obj: đối tượng kiểm tra
        * @returns đối tượng validate
        */
        username: function (obj) {
            var re = /^[a-zA-Z0-9_]+$/g;
            // Kết thúc xử lý
            return cts.helper.ValidateHelper.regex(obj, re);
        },
        /**
        * Kiểm tra password.
        * @param obj: đối tượng kiểm tra
        * @returns đối tượng validate
        */
        password: function (obj) {
            var re = /^[a-zA-Z0-9!@#$%^&*]+$/g;
            // Kết thúc xử lý
            return cts.helper.ValidateHelper.regex(obj, re);
        },
        /**
        * Kiểm tra email.
        * @param obj: đối tượng kiểm tra
        * @returns đối tượng validate
        */
        email: function (obj) {
            var re = /^(([^<>()\[\]\\.,;:\s@\"]+(\.[^<>()\[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/g;
            // Kết thúc xử lý
            return cts.helper.ValidateHelper.regex(obj, re);
        }
    }
});
/**
* @class
* Định nghĩa class 'cts.helper.PageHelper'
*/
cts.lang.Class.declare('cts.helper.PageHelper', {
    _static: {
        /* Định nghĩa phím tắc cho chức năng trên màn hình */
        KEYS: {
            F1: 112,
            F2: 113,
            F3: 114,
            F4: 115,
            F5: 116,
            F6: 117,
            F7: 118,
            F8: 119,
            F9: 120,
            F10: 121,
            F11: 122,
            F12: 123,
            Enter: 13,
            Tab: 9
        },
        /* Định nghĩa các phần tử được hỗ trợ trong trình tự tab */
        TAB_IDX_OBJ_SPT: 'a, area, button, input, object, select, textarea',
        TAB_IDX_MIN: 0,
        TAB_IDX_MAX: 9999,
        /**
        * Xử lý chính
        * @param obj: đối tượng setting
        */
        process: function (obj) {
            // Trường hợp là xử lý remote
            if (obj.http) {
                // Khởi tạo biến cục bộ
                var $http = obj.http;
                var fnSuccess = obj.success;
                var fnError = obj.error;
                // Lấy tham số request
                var data = obj.data;
                if ($.isFunction(data)) {
                    data = data();
                }
                // Kiểm tra tính hợp lệ
                if ($.isFunction(obj.validate)) {
                    // Lấy đối tượng validate
                    var validObj = obj.validate(data);
                    var rsVerify = cts.helper.ValidateHelper.verify(validObj);
                    // Trường hợp có dữ liệu không hợp lệ
                    if (!rsVerify) {
                        // Kết thúc xử lý
                        return;
                    }
                }
                // Khởi tạo replacer
                var replacer = function (key, value) {
                    if (value === undefined
                        || value === 'undefined'
                        || value === null) {
                        return '';
                    }
                    return value;
                }
                // Tạo đối tượng chung
                var baseObj = {
                    method: 'POST',
                    data: JSON.stringify({ request: data }, replacer)
                };
                // Hủy dữ liệu không cần thiết
                delete obj.http;
                delete obj.data;
                delete obj.success;
                delete obj.error;
                // Trường hợp data là null
                if (data === undefined) {
                    baseObj.data = JSON.stringify({});
                }
                // Thực thi jQuery.ajax
                return $http($.extend(baseObj, obj))
                .success(function (response, status, headers, config) {
                    // Lấy dữ liệu response
                    var jsonData = JSON.parse(response.d);
                    // Trường hợp phát sinh lỗi
                    if (jsonData.ResultFlag === undefined
                        || cts.helper.DataHelper.toBoolean(jsonData.ResultFlag)) {
                        // Thực thi hàm success
                        if (fnSuccess) {
                            fnSuccess(jsonData, status, headers, config);
                        }
                    } else {
                        // Thực thi hàm error
                        if (fnError) {
                            var error = {
                                Show: true,
                                Messages: jsonData.Messages
                            };
                            fnError(error, status, headers, config);
                        }
                    }
                })
                .error(function (response, status, headers, config) {
                    // alert(JSON.stringify(response));
                });
            }
            // Trường hợp là xử lý local
            obj();
        },
        /**
        * Giải mã html
        * @param data: chuỗi dữ liệu
        * @returns html đã giải mã
        */
        decodeHtml: function (data) {
            return $('<div/>').html(data).text();
        },
        /**
        * Mã hóa html
        * @param data: chuỗi dữ liệu
        * @returns html đã mã hóa
        */
        encodeHtml: function (data) {
            return $('<div/>').text(data).html();
        },
        /**
        * Xóa các thuộc tính của element
        * @param elem: element
        * @param attrs: Mảng thuộc tính
        */
        removeAttrs: function (elem, attrs) {
            for (var i in attrs) {
                elem.removeAttr(attrs[i]);
            }
        },
        /**
        * Lấy chuỗi locale
        * @returns chuỗi locale
        */
        getLang: function () {
            // Khởi tạo biến cục bộ
            var rs = 'vi';
            // Trường hợp ngôn ngữ khác null
            if (!cts.helper.CheckHelper.isNull(lang)) {
                rs = lang;
            }
            // Kết thúc xử lý
            return lang;
        },
        /**
        * Gán chuỗi locale
        * @param data: chuỗi locale
        */
        setLang: function (data) {
            // Kết thúc xử lý
            lang = data;
        },
        /**
        * Cập nhật lại trình tự tab
        */
        updateTabIndex: function () {
            $(cts.helper.PageHelper.TAB_IDX_OBJ_SPT).each(function () {
                var index = parseInt($(this).attr('tabindex'));
                if (isNaN(index)) {
                    $(this).attr('tabindex', -1);
                }
            });
        },
        /**
        * Áp dụng trình tự di chuyển tab cho các phím 'enter, tab, shift-enter, shift-tab'
        * theo nhóm thuộc tính 'group-index'
        */
        applyMoveTab: function () {
            var functionKeys = cts.helper.PageHelper.KEYS;
            var tabIdxObjSpt = cts.helper.PageHelper.TAB_IDX_OBJ_SPT;
            var tabIdxMin = cts.helper.PageHelper.TAB_IDX_MIN;
            var tabIdxMax = cts.helper.PageHelper.TAB_IDX_MAX;
            // Đăng ký sự kiện 'keydown'
            $(tabIdxObjSpt).keydown(function (e) {
                var key = e.which ? e.which : e.keyCode;
                if (key === functionKeys.Enter || key === functionKeys.Tab) {
                    // Trường hợp là button
                    if (cts.helper.CheckHelper.isButton(this) && key === functionKeys.Enter) {
                        $(this).click();
                        $(this).blur();
                        e.preventDefault();
                        return;
                    }
                    // Trường hợp có thuộc tính submit
                    if ($(this).attr('cts-submit') && key === functionKeys.Enter) {
                        var submit = $(this).attr('cts-submit');
                        if (!cts.helper.CheckHelper.isNull(submit)) {
                            return;
                        }
                    }
                    // Lấy nhóm cần focus
                    var grp = $(this).parents('[cts-tabgroup=true]:eq(0)');
                    if (grp.length === 0) {
                        grp = $(this).parents('body:eq(0)');
                    }
                    // Lấy các element có thể focus
                    var focusable = grp.find(tabIdxObjSpt).filter(_isFocusable);
                    // Lấy index của element hiện tại
                    var index = parseInt($(this).attr('tabindex'));
                    // Tiến hành xử lý next/previous
                    if (e.shiftKey) {
                        // Trường hợp previous
                        // Khởi tạo biến cục bộ
                        var prev, iprev = tabIdxMin;
                        // Duyệt các element có thể focus
                        $.each(focusable, function (i, elem) {
                            var ielem = parseInt($(elem).attr('tabindex'));
                            if (iprev < ielem && ielem < index) {
                                prev = elem;
                                iprev = ielem;
                            }
                        });
                        // Trường hợp là 'undefined'
                        if (prev === undefined) {
                            prev = _getMaxIndex(focusable);
                        }
                        // Tiến hành xử lý previous
                        _setFocus(e, prev);
                    } else {
                        // Trường hợp next
                        // Khởi tạo biến cục bộ
                        var next, inext = tabIdxMax;
                        // Duyệt các element có thể focus
                        $.each(focusable, function (i, elem) {
                            var ielem = parseInt($(elem).attr('tabindex'));
                            if (index < ielem && ielem < inext) {
                                next = elem;
                                inext = ielem;
                            }
                        });
                        // Trường hợp là 'undefined'
                        if (next === undefined) {
                            next = _getMinIndex(focusable);
                        }
                        // Tiến hành xử lý next
                        _setFocus(e, next);
                    }
                }
            });
            /**
            * Kiểm tra element có thể focus
            * @param i: index
            * @param elem: element
            * @returns {Boolean}
            */
            function _isFocusable(i, elem) {
                var rs = cts.helper.CheckHelper.isFocusable(elem)
                    && $(elem).attr('tabindex') >= tabIdxMin
                    && $(elem).attr('tabindex') <= tabIdxMax;
                return rs;
            };
            /**
            * Lấy tabindex nhỏ nhất
            * @param elems: Mảng element
            * @returns element với tabindex nhỏ nhất
            */
            function _getMinIndex(elems) {
                var rs, index = tabIdxMax;
                $.each(elems, function (i, elem) {
                    var ielem = parseInt($(elem).attr('tabindex'));
                    if (ielem < index) {
                        rs = elem;
                        index = ielem;
                    }
                });
                return rs;
            };
            /**
            * Lấy tabindex lớn nhất
            * @param elems: Mảng element
            * @returns element với tabindex lớn nhất
            */
            function _getMaxIndex(elems) {
                var rs, index = tabIdxMin;
                $.each(elems, function (i, elem) {
                    var ielem = parseInt($(elem).attr('tabindex'));
                    if (ielem > index) {
                        rs = elem;
                        index = ielem;
                    }
                });
                return rs;
            };
            /**
            * Gán focus vào element
            * @param e: Event 
            * @param elem: element
            */
            function _setFocus(e, elem) {
                $(elem).focus();
                e.preventDefault();
                if ($(elem).select && !$(elem).is(':button')) {
                    $(elem).select();
                    e.preventDefault();
                }
                return;
            };
        }
    }
});
/**
* @class
* Định nghĩa class 'cts.helper.StorageHelper'
*/
cts.lang.Class.declare('cts.helper.StorageHelper', {
    _static: {
        /** 
        * Lấy giá trị trong localStorage
        * @param name: tên biến
        * @returns giá trị
        */
        getValue: function (name) {
            return JSON.parse(localStorage.getItem(name))
        },
        /** 
        * Gán giá trị vào localStorage
        * @param name: tên biến
        * @param value: giá trị
        */
        setValue: function (name, value) {
            localStorage.setItem(name, JSON.stringify(value));
        },
        /** 
        * Xóa giá trị trong localStorage
        * @param name: tên biến
        */
        delValue: function (name) {
            localStorage.removeItem(name);
        }
    }
});
/**
* @class
* Định nghĩa class 'cts.helper.VariableHelper'
*/
cts.lang.Class.declare('cts.helper.VariableHelper', {
    _static: {
        /* Định nghĩa hằng */
        GLOBAL: 'global',
        /** 
        * Lấy giá trị trong storage
        * @param path: chuỗi đường dẫn
        * @param name: tên biến
        * @returns giá trị
        */
        getValue: function (path, name) {
            // Trường hợp path là null
            if (cts.helper.CheckHelper.isNull(path)) {
                path = cts.helper.VariableHelper.GLOBAL;
            }
            // Lấy giá trị trong localStorage
            var data = cts.helper.StorageHelper.getValue(path);
            // Trường hợp data là null
            if (cts.helper.CheckHelper.isNull(data)) {
                data = {};
            }
            // Kết thúc xử lý
            return data[name];
        },
        /** 
        * Gán giá trị vào storage
        * @param path: chuỗi đường dẫn
        * @param name: tên biến
        * @param value: giá trị
        */
        setValue: function (path, name, value) {
            // Trường hợp path là null
            if (cts.helper.CheckHelper.isNull(path)) {
                path = cts.helper.VariableHelper.GLOBAL;
            }
            // Lấy giá trị trong localStorage
            var data = cts.helper.StorageHelper.getValue(path);
            // Trường hợp data là null
            if (cts.helper.CheckHelper.isNull(data)) {
                data = {};
            }
            // Gán giá trị vào data
            data[name] = value;
            // Gán giá trị vào localStorage
            cts.helper.StorageHelper.setValue(path, data);
        },
        /** 
        * Xóa giá trị vào storage
        * @param path: chuỗi đường dẫn
        * @param name: tên biến
        */
        delValue: function (path, name) {
            // Trường hợp path là null
            if (cts.helper.DataCheckHelper.isNull(path)) {
                path = cts.helper.VariableHelper.GLOBAL;
            }
            // Lấy giá trị trong localStorage
            var data = cts.helper.StorageHelper.getValue(path);
            // Trường hợp data là null
            if (cts.helper.DataCheckHelper.isNull(data)) {
                data = {};
            }
            // Xóa giá trị trong data
            delete data[name];
            // Gán giá trị vào localStorage
            cts.helper.StorageHelper.setValue(path, data);
        }
    }
});
/**
* @class
* Định nghĩa class 'cts.helper.GridHelper'
*/
cts.lang.Class.declare('cts.helper.GridHelper', {
    _static: {
        /* Định nghĩa hằng */
        DEFAULT: {
            'order': [],
            'tabIndex': -1,
            'autoWidth': false,
            'searching': false,
            'lengthChange': false,
            'scrollCollapse': true,
            'paging': false,
            'info': false,
            'ordering': false,
            'classes': {
                'sSortAsc': 'sort-asc sorting_asc',
                'sSortDesc': 'sort-desc sorting_desc',
                'sSortable': 'sort sorting',
                'sScrollHead': 'header dataTables_scrollHead',
                'sScrollBody': 'row-fix row dataTables_scrollBody',
                'sInfo': 'pager-info dataTables_info',
                'sPaging': 'pager dataTables_paginate paging_'
            },
            'language': {
                'emptyTable': cts.helper.ResourceHelper.getMessage('I.MSG.00008')
            },
            'scrollX': '100%',
            'pageLength': 20
        },
        /** 
        * Lấy đối tượng thiết lập chung cho plugin dataTables
        * @param obj: đối tượng tham số
        */
        optBase: function (obj) {
            var width = '100%';
            if (obj && obj.width) {
                width = parseInt(obj.width);
            }
            var baseObj = {
                'scrollXInner': width
            };
            return $.extend(baseObj, cts.helper.GridHelper.DEFAULT);
        }
    }
});